class Guitar
   
  # Attributes
  attr_reader :mfc_class_name
  attr_reader :mfc_class_schema

  attr_accessor :number

  attr_reader :description
  attr_reader :preset
  attr_reader :initial_volume
  attr_reader :pan
  attr_reader :reverb
  attr_reader :chorus
  attr_reader :tremolo
  attr_reader :phaser
  attr_reader :capo
  attr_reader :tuning

  # Constants
  DEFAULT_NUMBER = 0
  DEFAULT_DESCRIPTION = "Untitled"
  DEFAULT_PRESET = MIDI_PRESET_ACOUSTIC_GUITAR_STEEL
  DEFAULT_INITIAL_VOLUME = 104
  DEFAULT_PAN = PAN_CENTER
  DEFAULT_REVERB = MIN_MIDI_CHANNEL_EFFECT_LEVEL
  DEFAULT_CHORUS = MIN_MIDI_CHANNEL_EFFECT_LEVEL
  DEFAULT_TREMOLO = MIN_MIDI_CHANNEL_EFFECT_LEVEL
  DEFAULT_PHASER = MIN_MIDI_CHANNEL_EFFECT_LEVEL
  DEFAULT_CAPO = 0
   
  MIN_PRESET = FIRST_MIDI_PRESET
  MAX_PRESET = LAST_MIDI_PRESET
   
  MIN_INITIAL_VOLUME = MIN_MIDI_CHANNEL_VOLUME
  MAX_INITIAL_VOLUME = MAX_MIDI_CHANNEL_VOLUME
   
  MIN_PAN = MIN_MIDI_CHANNEL_EFFECT_LEVEL
  MAX_PAN = MAX_MIDI_CHANNEL_EFFECT_LEVEL
  PAN_HARD_LEFT = MIN_PAN
  PAN_CENTER = 64
  PAN_HARD_RIGHT = MAX_PAN
   
  MIN_REVERB = MIN_MIDI_CHANNEL_EFFECT_LEVEL
  MAX_REVERB = MAX_MIDI_CHANNEL_EFFECT_LEVEL
   
  MIN_CHORUS = MIN_MIDI_CHANNEL_EFFECT_LEVEL
  MAX_CHORUS = MAX_MIDI_CHANNEL_EFFECT_LEVEL
   
  MIN_TREMOLO = MIN_MIDI_CHANNEL_EFFECT_LEVEL
  MAX_TREMOLO = MAX_MIDI_CHANNEL_EFFECT_LEVEL
   
  MIN_PHASER = MIN_MIDI_CHANNEL_EFFECT_LEVEL
  MAX_PHASER = MAX_MIDI_CHANNEL_EFFECT_LEVEL
   
  MIN_CAPO = 0
  MAX_CAPO = 12
      
  def initialize(number = DEFAULT_NUMBER, description = DEFAULT_DESCRIPTION, preset = DEFAULT_PRESET, initial_volume = DEFAULT_INITIAL_VOLUME, pan = DEFAULT_PAN, reverb = DEFAULT_REVERB, chorus = DEFAULT_CHORUS, tremolo = DEFAULT_TREMOLO, phaser = DEFAULT_PHASER, capo = DEFAULT_CAPO)

    mfc_class_name = "CGuitar"
    mfc_class_schema = 1

    @tuning = Tuning.new

    return false unless description
    return false unless valid_midi_preset?(preset)
    return false unless valid_midi_channel_volume?(initial_volume)
    return false unless valid_pan?(pan)
    return false unless valid_reverb?(reverb)
    return false unless valid_chorus?(chorus)
    return false unless valid_tremolo?(tremolo)
    return false unless valid_phaser?(phaser)
    return false unless valid_capo?(capo)
     
    @number = number
    @description = description
    @preset = preset
    @initial_volume = initial_volume
    @pan = pan
    @reverb = reverb
    @chorus = chorus
    @tremolo = tremolo
    @phaser = phaser
    @capo = capo

    return true

  end

  # Methods
  def description=(description)
    return false unless description
    @description = description
    return true
  end
   
  def valid_preset?(preset)
    return ((preset >= MIN_PRESET) && (preset <= MAX_PRESET))
  end
   
  def preset=(preset)
    return false unless valid_preset?(preset)
    @preset = preset
    return true
  end
   
  def valid_initial_volume?(initial_volume)
    return ((initial_volume >= MIN_INITIAL_VOLUME) && (initial_volume <= MAX_INITIAL_VOLUME))
  end
   
  def initial_volume=(initial_volume)
    return false unless valid_initial_volume?(initial_volume)
    @initial_volume = initial_volume
    return true
  end
   
  def valid_pan?(pan)
    return ((pan >= MIN_PAN) && (pan <= MAX_PAN))
  end
   
  def pan=(pan)
    return false unless valid_pan?(pan)
    @pan = pan
    return true
  end
   
  def valid_reverb?(reverb)
    return ((reverb >= MIN_REVERB) && (reverb <= MAX_REVERB))
  end
   
  def reverb=(reverb)
    return false unless valid_reverb?(reverb)
    @reverb = reverb
    return true
  end
   
  def valid_chorus?(chorus)
    return ((chorus >= MIN_CHORUS) && (chorus <= MAX_CHORUS))
  end
   
  def chorus=(chorus)
    return false unless valid_chorus?(chorus)
    @chorus = chorus
    return true
  end
   
  def valid_tremolo?(tremolo)
    return ((tremolo >= MIN_TREMOLO) && (tremolo <= MAX_TREMOLO))
  end
   
  def tremolo=(tremolo)
    return false unless valid_tremolo?(tremolo)
    @tremolo = tremolo
    return true
  end
   
  def valid_phaser?(phaser)
    return ((phaser >= MIN_PHASER) && (phaser <= MAX_PHASER))
  end
   
  def phaser=(phaser)
    return false unless valid_phaser?(phaser)
    @phaser = phaser
    return true
  end

  def valid_capo?(capo)
    return ((capo >= MIN_CAPO) && (capo <= MAX_CAPO))
  end
   
  def capo=(capo)
    return false unless valid_capo?(capo)
    @capo = capo
    return true
  end
   
  def uses_capo?
    return (@capo != MIN_CAPO)
  end
   
  def tuning=(tuning)
    return false unless tuning.valid?
    @tuning = tuning
    return true
  end
   
  def string_count
    return @tuning.string_count
  end
      
  def tuning_spelling
    return @tuning.spelling
  end

  # Serialization  
  def do_serialize(stream)
    write_byte(stream, @number)
    write_cstring(stream, @description)
    write_byte(stream, @preset)
    write_byte(stream, @initial_volume)
    write_byte(stream, @pan)
    write_byte(stream, @reverb)
    write_byte(stream, @chorus)
    write_byte(stream, @tremolo)
    write_byte(stream, @phaser)
    write_byte(stream, @capo)    
    @tuning.do_serialize(stream)
    return true
  end
     
  def do_deserialize(stream)
    @tuning = Tuning.new
    @number = read_byte(stream)
    @description = read_cstring(stream)
    @preset = read_byte(stream)
    @initial_volume = read_byte(stream)
    @pan = read_byte(stream)
    @reverb = read_byte(stream)
    @chorus = read_byte(stream)
    @tremolo = read_byte(stream)
    @phaser = read_byte(stream)
    @capo = read_byte(stream)
    @tuning.do_deserialize(stream)
  end
   
end
